package com.hyd.mvc;

import com.hyd.IndexController;
import com.hyd.annotation.Controller;
import com.hyd.annotation.RequestMapping;

import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.regex.Matcher;

public class HydMVC {
//    存放 一级注解-二级注解-方法 的map
    private static HashMap<String,HashMap<String, Method>> map_method = new HashMap<>();
//    存放 一级注解-类的实例化对象 的map
    private static HashMap<String, Object> map_object = new HashMap<>();

    /**
     * 方法执行函数
     * @param first_path 第一路径
     * @param second_path 第二路径
     */
    public static void mehtod_go(String first_path,String second_path){
//        如果map_object中没有fisrt_path，则不存在该注解的类
        if (map_object.get(first_path)==null){
            System.out.println("没有一个类有"+first_path+"注解");
        }else {
            if (map_method.get(first_path).get(second_path)==null){
                System.out.println(first_path+"下没有"+second_path+"注解"+"的方法");
            }else{
                try {
                    map_method.get(first_path).get(second_path).invoke(map_object.get(first_path));
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 扫描获取类实例化对象以及方法
     * @param path
     * @param packageName 包名
     */

    public static void scanner(String path,String packageName){
//        扫描当前所有的文件
        List<String> paths = traverseFolder2(path);
//        遍历拿到的文件路径
        for (String path1 : paths) {
//              path1为：C:\ttt\imitating_spring_mvc\out\production\imitating_spring_mvc\com\heaboy\IndexController.class
//              先拿到文件名 例：IndexController.class
            path1=path1.substring(path.length()-1);
            try{
                //            构建类名
//            因为可能存在多级路径，例如：www/IndexController.class,所以还需要进行一些小处理，不能直接拼接
//            File.separator代表文件分隔符
//            Matcher.quoteReplacement确保了文件分隔符在替换过程中被正确地转义，以防包含任何正则表达式的特殊字符。它返回一个适合用于正则表达式替换的字符串。
                String ClassName = packageName + "." + path1.replaceAll(Matcher.quoteReplacement(File.separator),".");
//            去掉文件名中的.class后缀
                String load_className = ClassName.replace(".class","");
//            通过类加载器加载类
                Class<?> cl = ClassLoader.getSystemClassLoader().loadClass(load_className);
//            用写好的检查注解方法（isController）判断cl是否有Controller注解
                if(isController(cl)){
//              用写好的检查注解方法（isRequestMapping）判断cl是否有RequestMapping注解
                    if (isRequestMapping(cl)){
//                    如果有就获取类上RequestMapping注解的实例
                        RequestMapping requestMapping_first = getRequestMapping(cl);
//                    判断map_method中是否已经存在了该一级注解
                        if (map_method.containsKey(requestMapping_first.value())){
//                        已经存在该一级注解，则抛出异常
                            throw new RuntimeException("包含多个注解:"+requestMapping_first.value());
                        }else {
//                        不存在,添加至map_method中
                            map_method.put(requestMapping_first.value(),new HashMap<>());
//                        添加类的实例化对象到
                            map_object.put(requestMapping_first.value(),cl.newInstance());
                        }
//                    获取类中所有的方法
                        Method[] declareMethods = cl.getDeclaredMethods();
//                    遍历所有方法
                        for (Method method : declareMethods) {
                            if (isRequestMapping(method)){
                                RequestMapping requestMapping_second = getRequestMapping(method);
//                            判断该二级注解是否已经存在
                                if (map_method.get(requestMapping_first.value()).containsKey(requestMapping_second.value())){
//                                存在抛出错误
                                    throw new RuntimeException("方法注解已经存在："+requestMapping_second.value());
                                }else {
//                                不存在就将方法放入map_method
                                    map_method.get(requestMapping_first.value()).put(requestMapping_second.value(),method);
                                }
                            }
                        }
                    }else{
                        throw new RuntimeException("该类有没RequestMapping注解");
                    }
                }
            }catch (Exception e){
                System.out.println(e);
            }
        }

    }



    /**
     * 扫描文件
     * @param path 绝对路径
     * @return List<String> 文件绝对路径集合
     * C:\ttt\imitating_spring_mvc\out\production\imitating_spring_mvc\com\heaboy\IndexController.class
     */
    private static List<String> traverseFolder2(String path) {
//        当前路径下的文件和文件夹
        File file = new File(path);
//        返回的文件集合
        List<String> file_list = new ArrayList<>();

        if (file.exists()){
//            放文件夹
            LinkedList<File> list = new LinkedList<>();

//            存储过程中要处理的文件
            File[] files = file.listFiles();

            for (File file1 : files) {
//                如果当前文件是文件夹就把它放到list里面
                if (file1.isDirectory()){
                    list.add(file1);
                }else { //不是就将该文件的绝对路径放到返回列表中file_list
                    file_list.add(file1.getAbsolutePath());
                }
            }
//            申请一个临时变量
            File file_temp;
//            当存放文件夹的队列不为空时，执行以下操作
            while (!list.isEmpty()){
//                取出第一个文件夹来处理
                file_temp=list.removeFirst();
//                使用上面申请的FIle[]来存放file_temp中的文件
                files=file_temp.listFiles();
//                处理files中的文件,同上，文件夹放到list中，文件放到file_list中
                for (File file1 : files) {
                    if (file1.isDirectory()){
                        list.add(file1);
                    }else {
                        file_list.add(file1.getAbsolutePath());
                    }
                }
            }
        }else{
//            如果没有任何文件，则不做处理
        }
        return file_list;
    }

//    判断类是否有Controller注解
    private static boolean isController(Class cl){
        Annotation annotation = cl.getAnnotation(Controller.class);
        if(annotation!=null){
            return  true;
        }
        return false;
    }

//    判断类是否有RequestMapping注解
    private static boolean isRequestMapping(Class cl){
        Annotation annotation = cl.getAnnotation(RequestMapping.class);
        if(annotation!=null){
            return  true;
        }
        return false;
    }
//    获取类的RequestMapping注解的实例
    private static RequestMapping getRequestMapping(Class<?> cl) {
        Annotation annotation = cl.getAnnotation(RequestMapping.class);
        if (annotation instanceof  RequestMapping){
            return (RequestMapping) annotation;
        }
        return null;
    }

    //    判断方法是否有RequestMapping注解
    private static boolean isRequestMapping(Method method) {
        Annotation annotation = method.getAnnotation(RequestMapping.class);
        if (annotation!=null){
            return true;
        }
        return false;
    }
//    获取方法上的RequestMapping注解的实例
    private static RequestMapping getRequestMapping(Method method) {
        Annotation annotation  = method.getAnnotation(RequestMapping.class);
        if (annotation instanceof RequestMapping){
            return (RequestMapping) annotation;
        }
        return null;
    }

}
